﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using MyClub.Model;
using System.Globalization;

namespace MyClub.Web
{
    /// <summary>
    /// Provides <see cref="SiteMapNode">nodes</see> to various web controls.
    /// </summary>
    /// <see cref="System.Web.UI.WebControls.SiteMapPath"/>
    /// <see cref="System.Web.UI.WebControls.SiteMapDataSource"/>
    public sealed class PostSiteMapProvider : SiteMapProvider
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="PostSiteMapProvider"/> class.
        /// </summary>
        public PostSiteMapProvider()
        {
        }

        /// <summary>
        /// When overridden in a derived class, retrieves a <see cref="T:System.Web.SiteMapNode"/> object that represents the page at the specified URL.
        /// </summary>
        /// <param name="rawUrl">A URL that identifies the page for which to retrieve a <see cref="T:System.Web.SiteMapNode"/>.</param>
        /// <returns>
        /// A <see cref="T:System.Web.SiteMapNode"/> that represents the page identified by <paramref name="rawURL"/>; otherwise, null, if no corresponding <see cref="T:System.Web.SiteMapNode"/> is found or if security trimming is enabled and the <see cref="T:System.Web.SiteMapNode"/> cannot be returned for the current user.
        /// </returns>
        public override SiteMapNode FindSiteMapNode(string rawUrl)
        {
            string path = rawUrl;

            using (var entities = new MyClubEntities())
            {
                var postQuery = from p in entities.Post
                                    where string.Compare(p.Path, path, StringComparison.OrdinalIgnoreCase) == 0
                                    select p;

                var post = postQuery.FirstOrDefault();
                if (post == null)
                    return null;

                return PostToSiteMapNode(post);
            }
        }

        /// <summary>
        /// When overridden in a derived class, retrieves the child nodes of a specific <see cref="T:System.Web.SiteMapNode"/>.
        /// </summary>
        /// <param name="node">The <see cref="T:System.Web.SiteMapNode"/> for which to retrieve all child nodes.</param>
        /// <returns>
        /// A read-only <see cref="T:System.Web.SiteMapNodeCollection"/> that contains the immediate child nodes of the specified <see cref="T:System.Web.SiteMapNode"/>; otherwise, null or an empty collection, if no child nodes exist.
        /// </returns>
        public override SiteMapNodeCollection GetChildNodes(SiteMapNode node)
        {
            if (node == null)
                throw new ArgumentNullException("node");

            var childNodes = new SiteMapNodeCollection();
            // Currently no child nodes.
            // This might be expanded in the future to include
            // pages, images etc...
            return childNodes;
        }

        /// <summary>
        /// When overridden in a derived class, retrieves the parent node of a specific <see cref="T:System.Web.SiteMapNode"/> object.
        /// </summary>
        /// <param name="node">The <see cref="T:System.Web.SiteMapNode"/> for which to retrieve the parent node.</param>
        /// <returns>
        /// A <see cref="T:System.Web.SiteMapNode"/> that represents the parent of <paramref name="node"/>; otherwise, null, if the <see cref="T:System.Web.SiteMapNode"/> has no parent or security trimming is enabled and the parent node is not accessible to the current user.
        /// Note:<see cref="M:System.Web.SiteMapProvider.GetParentNode(System.Web.SiteMapNode)"/> might also return null if the parent node belongs to a different provider. In this case, use the <see cref="P:System.Web.SiteMapNode.ParentNode"/> property of <paramref name="node"/> instead.
        /// </returns>
        public override SiteMapNode GetParentNode(SiteMapNode node)
        {
            if (node == null)
                throw new ArgumentNullException("node");

            int id;
            if (!int.TryParse(node.Key, out id))
                throw new InvalidOperationException();

            using (var entities = new MyClubEntities())
            {
                var categoryQuery = from p in entities.Post
                                    where p.Id == id
                                    select p.Category;

                var category = categoryQuery.FirstOrDefault();
                if (category == null)
                    throw new InvalidOperationException();

                return CategoryToSiteMapNode(category);
            }
        }

        /// <summary>
        /// When overridden in a derived class, retrieves the root node of all the nodes that are currently managed by the current provider.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.Web.SiteMapNode"/> that represents the root node of the set of nodes that the current provider manages.
        /// </returns>
        protected override SiteMapNode GetRootNodeCore()
        {
            return null;
        }

        private static SiteMapNode CategoryToSiteMapNode(Category category)
        {
            if (category == null)
                throw new ArgumentNullException("category");

            return SiteMap.Providers["Categories"].FindSiteMapNodeFromKey(category.Id.ToString(CultureInfo.InvariantCulture));
        }

        private SiteMapNode PostToSiteMapNode(Post post)
        {
            if (post == null)
                throw new ArgumentNullException("post");

            var node = new SiteMapNode(this, post.Id.ToString(CultureInfo.InvariantCulture));
            node.Title = post.Title;
            node.Description = post.Summary;
            node.Url = "~" + post.Path;
            return node;
        }
    }
}
